using System.Collections.Generic;
using System.IO;
using SpoonCore2.Client;
using SpoonCore2.Message;

namespace SpoonCore2.Service.Broadcast
{
	public class BroadcastGroup
	{
		private readonly BroadcastService _service;
		private readonly SpoonIdentifier _id;
		private readonly SortedList<int, IHandlerItem> _handlers = new SortedList<int, IHandlerItem>();

		public delegate void ReceiveBroadcastMessageHandler<T>(BroadcastGroup group, T message) where T : IMessage;

		internal BroadcastGroup(BroadcastService service, SpoonIdentifier id)
		{
			_service = service;
			_id = id;
		}

		public SpoonIdentifier Id { get { return _id; } }

		public void Send(IMessage message)
		{
			MemoryStream stream = new MemoryStream();
			BinaryWriter bw = new BinaryWriter(stream);

			bw.Write(message.GetType().GetHashCode());
			message.GetBytes(bw);

			BroadcastMessage msg = new BroadcastMessage();
			msg.BroadcastGroup = Id;
			msg.Data = stream.ToArray();

			_service.Manager.Network.GetClientInfo(SpoonIdentifier.Empty).Send(msg); //TODO just for test
		}

		public void Receive(byte[] data)
		{
			MemoryStream stream = new MemoryStream();
			BinaryReader br = new BinaryReader(stream);

			int msgId = br.ReadInt32();
			if (_handlers.ContainsKey(msgId)) _handlers[msgId].Dispache(_service, this, br);
		}

		public void Register<T>(ReceiveBroadcastMessageHandler<T> handler) where T : IMessage, new()
		{
			_handlers.Add(typeof(T).FullName.GetHashCode(), new HandlerItem<T>(handler));
		}

		private interface IHandlerItem
		{
			void Dispache(IService service, BroadcastGroup sender, BinaryReader reader);
		}

		private class HandlerItem<T> : IHandlerItem where T : IMessage, new()
		{
			private readonly ReceiveBroadcastMessageHandler<T> _handler;

			public HandlerItem(ReceiveBroadcastMessageHandler<T> handler)
			{
				_handler = handler;
			}

			public void Dispache(IService service, BroadcastGroup sender, BinaryReader reader)
			{
				T msg = new T();
				msg.SetBytes(service, reader);
				_handler(sender, msg);
			}
		}
	}
}